package com.xgk.boot.module.core.service.permission;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mzt.logapi.context.LogRecordContext;
import com.mzt.logapi.starter.annotation.LogRecord;
import com.xgk.boot.framework.common.constant.ErrorCodeConstants;
import com.xgk.boot.framework.common.enums.CommonStatusEnum;
import com.xgk.boot.framework.common.exception.util.ServiceExceptionUtil;
import com.xgk.boot.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.xgk.boot.framework.security.core.LoginUser;
import com.xgk.boot.framework.security.core.util.SecurityFrameworkUtils;
import com.xgk.boot.module.core.dal.entity.order.OrderLogDO;
import com.xgk.boot.module.core.dal.entity.permission.RoleDO;
import com.xgk.boot.module.core.dal.entity.permission.UserRoleDO;
import com.xgk.boot.module.core.dal.iservice.UserRoleService;
import com.xgk.boot.module.core.dal.mapper.permission.UserRoleMapper;
import com.xgk.boot.module.core.dal.redis.RedisKeyConstants;
import com.xgk.boot.module.core.enums.permission.RoleCodeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import static com.xgk.boot.module.core.enums.LogRecordConstants.*;

/**
 * <p>
 * 订单日志表 服务实现类
 * </p>
 *
 * @author yfbao
 * @since 2025-06-14
 */
@Slf4j
@Service
public class UserRoleServiceImpl extends ServiceImpl<UserRoleMapper, UserRoleDO> implements UserRoleService {

    @Autowired
    private RoleService roleService;
    @Autowired
    private UserRoleServiceImpl self;

    @Transactional
    @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_ROLE_CREATE, bizNo = "{{#userRole.id}}",
            success = SYSTEM_USER_ROLE_CREATE_SUCCESS)
    @CacheEvict(value = RedisKeyConstants.USER_IS_ADMIN, key = "#userId")
    public boolean setCustomerRole(Long userId){
        String code = RoleCodeEnum.CRM.getCode();
        RoleDO roleFromCacheByCode = roleService.getRoleFromCacheByCode(code);
        if(roleFromCacheByCode ==null){
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.ROLE_NOT_EXISTS,code);
        }
        List<UserRoleDO> userRoles = getUserRoles(userId);
        if(!CollUtil.isEmpty(userRoles)){
            for (UserRoleDO userRole : userRoles) {
                if(userRole.getRoleId().equals(roleFromCacheByCode.getId())){
                    return true;
                }
            }
        }
        UserRoleDO userRoleDO =new UserRoleDO();
        userRoleDO.setUserId(userId);
        userRoleDO.setRoleId(roleFromCacheByCode.getId());
        boolean saveStatus = saveUserRole(userRoleDO);
        LogRecordContext.putVariable("userRole", userRoleDO);
        return saveStatus;
    }

    @Transactional
    @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_ROLE_CREATE, bizNo = "{{#userRole.id}}",
            success = SYSTEM_USER_ROLE_CREATE_SUCCESS)
    @CacheEvict(value = RedisKeyConstants.USER_IS_ADMIN, key = "#userId")
    public boolean setAdminRole(Long userId){
        String code = RoleCodeEnum.ADMIN.getCode();
        RoleDO roleFromCacheByCode = roleService.getRoleFromCacheByCode(code);
        if(roleFromCacheByCode ==null){
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.ROLE_NOT_EXISTS,code);
        }
        List<UserRoleDO> userRoles = getUserRoles(userId);
        if(!CollUtil.isEmpty(userRoles)){
            for (UserRoleDO userRole : userRoles) {
                if(userRole.getRoleId().equals(roleFromCacheByCode.getId())){
                    return true;
                }
            }
        }
        UserRoleDO userRoleDO =new UserRoleDO();
        userRoleDO.setUserId(userId);
        userRoleDO.setRoleId(roleFromCacheByCode.getId());
        boolean saveStatus = saveUserRole(userRoleDO);
        LogRecordContext.putVariable("userRole", userRoleDO);
        return saveStatus;
    }

    @Transactional
    @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_ROLE_CREATE, bizNo = "{{#userRole.id}}",
            success = SYSTEM_USER_ALL_ROLE_DELETE_SUCCESS)
    @CacheEvict(value = RedisKeyConstants.USER_IS_ADMIN, key = "#userId")
    public boolean deleteUserRole(Long userId){
        List<UserRoleDO> userRoles = getUserRoles(userId);
        if(userRoles.isEmpty()){
            return true;
        }
        List<Long> ids = new ArrayList<>();
        for (UserRoleDO userRole : userRoles) {
            ids.add(userRole.getId());
        }
        boolean status = self.removeByIds(ids);
        LogRecordContext.putVariable("userId", userId);
        return status;
    }

    @Transactional
    public boolean saveUserRole(UserRoleDO userRoleDO){
        return this.save(userRoleDO);
    }


    public List<UserRoleDO> getUserRoles(Long userId){
        LambdaQueryWrapperX queryWrapperX = new LambdaQueryWrapperX<UserRoleDO>().eq(UserRoleDO::getUserId, userId);
        List<UserRoleDO> list = this.list(queryWrapperX);
        return list;
    }

    public Boolean isCurrentUserAdmin(){
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        if(loginUser == null){
            return false;
        }
        return self.isAdmin(loginUser.getId());
    }

    /**
     * 判断用户是否为管理员
     * @param userId
     * @return
     */
    @Cacheable(value = RedisKeyConstants.USER_IS_ADMIN, key = "#userId")
    public Boolean isAdmin(Long userId){
        List<UserRoleDO> userRoles = self.getUserRoles(userId);
        Set<Long> roleIds =new HashSet<>();
        for (UserRoleDO userRole : userRoles) {
            roleIds.add(userRole.getRoleId());
        }
        List<RoleDO> roleList = roleService.getRoleList(roleIds);
        for (RoleDO roleDO : roleList) {
            if(roleDO.getStatus().equals(CommonStatusEnum.DISABLE.getStatus()) ){
                continue;
            }
            if(roleDO.getCode().equals(RoleCodeEnum.ADMIN.getCode())){
                return true;
            }
        }
        return false;
    }
}
